//
//  YMCameraViewController.swift
//  YMMedical
//
//  Created by y s on 2023/6/27.
//

import UIKit
import AVFoundation
import CoreGraphics

public typealias finishPhotoBlock = (_ detectionId: String)->()

@objcMembers class YMCameraViewController: UIViewController {
    let session = AVCaptureSession()
    let photoOutput = AVCapturePhotoOutput()
    let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: AVCaptureDevice.Position.back)!
    var previewLayer = AVCaptureVideoPreviewLayer()
    
    lazy var btnStart: UIButton = {
        let result = UIButton(type: .custom)
        result.setImage(UIImage(named: "check_camra_button_icon"), for: .normal)
        result.addTarget(self, action: #selector(startCameraAction), for: .touchUpInside)
        result.isHidden = true
        return result
    }()
    lazy var btnBack: UIButton = {
        let btn = UIButton(type: .custom)
        btn.setImage(UIImage(named: "tools_nav_white_back"), for: .normal)
        btn.addTarget(self, action: #selector(clickBackAction), for: .touchUpInside)
        return btn
    }()
    
    lazy var vPreBox: YMCameraPreviewView = {
        let result = YMCameraPreviewView()
        result.clickBlock = {[weak self] in
            self?.startClickAction()
        }
        return result
    }()
    lazy var lblTips: UILabel = {
        let result = UILabel()
        result.textColor = STheme.D8
        result.font = SFitUtil.fitFont(12)
        result.numberOfLines = 0
        result.isHidden = true
        return result
    }()
    lazy var vFocus: UIView = {
        let result = UIView(frame: CGRectMake(0, 0, SFitUtil.fit(80), SFitUtil.fit(80)))
        result.backgroundColor = .clear
        result.layer.borderColor = UIColor.yellow.cgColor
        result.layer.borderWidth = 1
        result.isHidden = true
        return result
    }()
    
    static var iso: Float! = 100
    static var exposure: CMTime! = CMTimeMake(value: 1,timescale: 100)
    var isStart:Bool = false
    var isImageCal: Bool = false
    var preIsMinExposure = false
    var adjustNum = 0
    var adjustISO = 0
    var cameraBtnIsPressed = false //是否按下拍照按钮
    var isAddDevice = false //是否添加过device
    var focusPoint = CGPoint(x: 0.5, y: 0.5)
    public var finishBlock: finishPhotoBlock?
    public var dictInfor: [String : Any]?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setUI()
    }
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        UIApplication.shared.isIdleTimerDisabled = true
    }
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        UIApplication.shared.isIdleTimerDisabled = false
        preIsMinExposure = false
        adjustNum = 0
        adjustISO = 0
    }
    

    func setUI() {
        addCameraSetting()
        previewLayer = AVCaptureVideoPreviewLayer(session: self.session)
        previewLayer.frame = view.bounds
        previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
        view.layer.addSublayer(previewLayer)
    
        view.addSubview(lblTips)
        view.addSubview(btnStart)
        view.addSubview(vPreBox)
        view.addSubview(vFocus)
        view.addSubview(btnBack)
        
        btnStart.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            make.size.equalTo(SFitUtil.fitSize(100, height: 100))
            make.bottom.equalTo(-SFitUtil.fit(28)-SFitUtil.safeBottom)
        }
        btnBack.snp.makeConstraints { make in
            make.left.equalTo(0)
            make.top.equalTo(StatusBarHeight)
            make.size.equalTo(SFitUtil.fitSize(46, height: 44))
        }
        vPreBox.snp.makeConstraints { make in
            make.top.left.right.equalToSuperview();
            make.bottom.equalTo(SFitUtil.fit(-15)-SFitUtil.safeBottom)
        }
        vPreBox.setNeedsDisplay()
        lblTips.snp.makeConstraints { make in
            make.left.equalTo(SFitUtil.fit(10))
            make.bottom.equalTo(btnStart.snp.top)
            make.width.equalTo(SFitUtil.fit(250))
        }
        
        DispatchQueue.global().async { [weak self] in
            self?.session.startRunning()
        }
        
        view.isUserInteractionEnabled = true
        let tap = UITapGestureRecognizer(target: self, action: #selector(tapViewAction(_:)))
        view.addGestureRecognizer(tap)
    }
    func addCameraSetting(){
        session.beginConfiguration()
        session.sessionPreset = .photo
        if !isAddDevice {
            session.addInput(try! AVCaptureDeviceInput(device: device))
            session.addOutput(photoOutput)
            isAddDevice = true
        }
        do {
            try device.lockForConfiguration()
            device.setExposureModeCustom(duration: YMCameraViewController.exposure, iso: YMCameraViewController.iso, completionHandler: {(time) in})
            if device.isFocusModeSupported(.continuousAutoFocus) {
                device.focusPointOfInterest = focusPoint
                device.focusMode = .continuousAutoFocus
            }
            device.unlockForConfiguration()
        } catch {
            debugPrint(error)
        }
        
        session.commitConfiguration()
    }
    
    // 尝试使用新参数拍照，并判断参数是否最佳
    @objc func tryCaptureWithSetting (){

        let photoOutputSettings: Dictionary<String, Any> = [
            AVVideoCodecKey : AVVideoCodecType.jpeg
        ];
        addCameraSetting()
        var settings = AVCapturePhotoSettings(format: photoOutputSettings)
        settings.flashMode = .off
        if isImageCal && cameraBtnIsPressed {
            if let rawFormat = photoOutput.availableRawPhotoPixelFormatTypes.first{
                settings = AVCapturePhotoSettings(rawPixelFormatType: OSType(rawFormat))
                photoOutput.capturePhoto(with: settings, delegate: self)
            }
        } else {
            photoOutput.capturePhoto(with: settings, delegate: self)
        }
    }
    
    //开始检测
    func startClickAction() {
        isStart = true
        adjustNum = 0
        adjustISO = 0
        
        tryCaptureWithSetting()
        
        SHUD.showDarkWait(view, text: YMBridging.kLanguage("camera_para_loading_txt"), afterShow: 0)
        lblTips.isHidden = !YMMyModel.shared().showCameraTips
        btnBack.bringSubviewToFront(view)
        
    }

    //开始拍照
    @objc func startCameraAction(){
        lblTips.isHidden = true
//     print("********exposure=\(YMCameraViewController.exposure),iso=\(YMCameraViewController.iso)")
        cameraBtnIsPressed = true
        tryCaptureWithSetting()
    }
    
    
    //返回
    func clickBackAction() {
        dismiss(animated: true)
    }
    
    private func uploadPhoto(_ imgData: Data){
        let alert = YMCheckGenerateReportAlert()
        alert.show()
        let arcNum = arc4random() % 100
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyyMMddHHmmss"
        let timeStr = dateFormatter.string(from: Date())
        
        var fileName = YMMyModel.shared().userPhone+"0"+timeStr
        if arcNum < 10 {
            fileName = fileName+"0\(arcNum)"
        }else{
            fileName = fileName+"\(arcNum)"
        }
        fileName = fileName+".dng"
        
        YMCheckService.requestUploadFile(with: imgData, fileName: fileName, mimeType: "image/jpeg") { [weak self] (pathUrl, name) in
            
            self?.addCheckRecordData(name, alert)
        } failure: {[weak self] message in
            
            self?.loadFailureAction("上传失败，请重试",alert)
        }
    }
    
    func addCheckRecordData(_ fileName: String, _ alert: YMCheckGenerateReportAlert){
        if dictInfor != nil {
            dictInfor!["imageFilename"] = SDataUtil.stringOf(fileName, valid: "")
            YMCheckService.requestCheckAddDetectionRecord(withDict: dictInfor!) {[weak self] detectionId in
                DispatchQueue.main.async {
                    alert.dismiss()
                    self?.clickBackAction()
                    if self?.finishBlock != nil{
                        self?.finishBlock!(detectionId)
                    }
                }
            } failure: {[weak self] message in
                self?.loadFailureAction(message,alert)
            }
        }else{
            loadFailureAction(YMBridging.kLanguage("report_Failed_txt"),alert)
        }
    }
    func loadFailureAction(_ message: String, _ alert: YMCheckGenerateReportAlert){
        DispatchQueue.main.async {[weak self] in
//            SHUD.showInfo(message)
            alert.dismiss()
            if self?.finishBlock != nil{
                self?.finishBlock!("")
            }
            self?.clickBackAction()
        }
    }
    
    func tapViewAction(_ sender: UITapGestureRecognizer){
        let point = sender.location(in: sender.view)
        let size = view.bounds.size
        let focusPoint = CGPoint(x: point.y/size.height, y: 1-(point.x/size.width))
        do {
            try device.lockForConfiguration()
            if device.isFocusModeSupported(.continuousAutoFocus) {
                device.focusPointOfInterest = focusPoint
                device.focusMode = .continuousAutoFocus
                self.focusPoint = focusPoint
            }
            device.unlockForConfiguration()
            
            vFocus.center = point
            vFocus.isHidden = false
            UIView.animate(withDuration: 0.3) {
                self.vFocus.transform = CGAffineTransformMakeScale(1.25, 1.25)
            } completion: { finished in
                UIView.animate(withDuration: 0.5) {
                    self.vFocus.transform = CGAffineTransformIdentity
                }completion: { finished in
                    self.vFocus.isHidden = true
                }
            }
        } catch {
            debugPrint(error)
        }
    }
}

extension YMCameraViewController: AVCapturePhotoCaptureDelegate {
    
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        if cameraBtnIsPressed{
            session.stopRunning()
            if let imgData = photo.fileDataRepresentation(){
                session.stopRunning()
                uploadPhoto(imgData)
            }else{
                DispatchQueue.main.async {
                    SHUD.showInfo("拍照失败，请稍后重试")
                }
                clickBackAction()
            }
        }else{
            if isStart, isImageCal == false {
                
                let arrRed = imageFromSampleBuffer(photo: photo)
                if arrRed.count < 100 {
                    isImageCal = false
                    tryCaptureWithSetting()
                }else{
                    let average = calculateRedAverage(arrRed: arrRed)
                    print("**********average=\(average)")
                    if average < 180 || average > 230{
                
                        changeCameraExposure(average: average)
                        tryCaptureWithSetting()
                        if adjustISO >= 5 {
                            isImageCal = true
                            DispatchQueue.main.async {[weak self] in
                                SHUD.hide(self?.view)
                                self?.btnStart.isHidden = false
                            }
                        }else{
                            isImageCal = false
                        }
                    }else{
                        isImageCal = true
                        DispatchQueue.main.async {[weak self] in
                            SHUD.hide(self?.view)
                            self?.btnStart.isHidden = false
                        }
                    }
                }
            }
        }
    }
    
    private func calculateRedAverage(arrRed :Array<Int>) -> Float{
        var sum: Int = 0
        for index in 0..<100 {
            sum = sum + Int(arrRed[index])
        }
        var average = Float(sum)/100.0
//                device.maxExposureDuration minExposureDuration
        if (average <= 0){
            average = 1
        }
        return average;
    }
    //调节相机曝光时间
    private func changeCameraExposure(average: Float)
    {
        let timeScale = YMCameraViewController.exposure.timescale
        var timeValue = YMCameraViewController.exposure.value
        let preTime = Float(timeValue)/Float(timeScale)
        if preIsMinExposure == false{
            adjustNum += 1
            if average <= 20 {
                //将当前曝光时间乘以2
                YMCameraViewController.exposure = CMTimeMake(value: timeValue*2, timescale: timeScale)
                
            }else if average > 20 && average < 180 {
                //将205除以平均值后的值乘以当前曝光时间做为新的曝光时间
                let nexTime: Float = Float(205)/Float(average)
                let fTime = nexTime * preTime
                let strTime = String(format:"%.4f",fTime)
                timeValue = Int64(Float(strTime)!*10000)
                YMCameraViewController.exposure = CMTimeMake(value: timeValue, timescale: 10000)
            }else if average > 230 {
                //减少曝光时间，将曝光时间减少至原来的1/2
                let time = CMTimeMake(value: timeValue, timescale: timeScale*2)
                YMCameraViewController.exposure = time
            }
            
            let nowTimeScale = YMCameraViewController.exposure.timescale
            let nowTimeValue = YMCameraViewController.exposure.value
            let nowTime = Float(nowTimeValue)/Float(nowTimeScale)
            if (nowTime > 0.1){
                YMCameraViewController.exposure = CMTimeMake(value: 1, timescale: 10)
            }
            if YMCameraViewController.exposure < device.activeFormat.minExposureDuration {
                YMCameraViewController.exposure = device.activeFormat.minExposureDuration
            }
            if YMCameraViewController.exposure > device.activeFormat.maxExposureDuration{
                YMCameraViewController.exposure = device.activeFormat.maxExposureDuration
            }
        }
        
        //调节ISO
        let preISO = YMCameraViewController.iso
        
        if preIsMinExposure {
            adjustISO += 1
            if average <= 21 {
                YMCameraViewController.iso = YMCameraViewController.iso * 2
            }else if average > 21 && average < 180 {
                let isoNext: Float = Float(205)/Float(average)
                YMCameraViewController.iso = YMCameraViewController.iso * isoNext
            }else if average > 230{
                YMCameraViewController.iso = YMCameraViewController.iso * 0.5
            }
            if YMCameraViewController.iso > device.activeFormat.maxISO {
                YMCameraViewController.iso = device.activeFormat.maxISO
            }
            if YMCameraViewController.iso < device.activeFormat.minISO {
                YMCameraViewController.iso = device.activeFormat.minISO
            }
        }
        
        let nowTimeScale = YMCameraViewController.exposure.timescale
        let nowTimeValue = YMCameraViewController.exposure.value
        let nowTime = Float(nowTimeValue)/Float(nowTimeScale)
        if (nowTime == preTime || adjustNum >= 5){
            preIsMinExposure = true
        }
        let scaleRe = YMCameraViewController.exposure.timescale
        let valueRe = YMCameraViewController.exposure.value
        let tipsStr = "第\(adjustNum+adjustISO)次调节：曝光时间=\(Float(valueRe)/Float(scaleRe)),ISO=\(YMCameraViewController.iso!)\n百点红色光强均值=\(average)\n\n"
        
        if preIsMinExposure && YMCameraViewController.iso == preISO {
            adjustISO = 5
        }
        DispatchQueue.main.async {[weak self] in
            self?.lblTips.text = (self?.lblTips.text ?? "")+tipsStr
        }
    }
        
        
    private func imageFromSampleBuffer(photo :AVCapturePhoto) -> Array<Int> {
        
        guard let cgImage = photo.cgImageRepresentation(),
            let data = cgImage.dataProvider?.data,
            let bytes = CFDataGetBytePtr(data) else {
            fatalError("Couldn't access image data")
        }
        assert(cgImage.colorSpace?.model == .rgb)

        let bytesPerPixel = cgImage.bitsPerPixel / cgImage.bitsPerComponent
        
        var redValueOfAllPts:[Int]=[]
        // 获取所有点的红色光强值
        for y in 0 ..< cgImage.height {
            for x in 0 ..< cgImage.width {
                let offset = (y * cgImage.bytesPerRow) + (x * bytesPerPixel)
                let r = bytes[offset]
                if  r > 0 {
                    redValueOfAllPts.append(Int(r))
                }
            }
        }
//        var i = 0
//        let l = cgImage.height*cgImage.width*bytesPerPixel
//        while i<l {
//            let r = bytes[i]
//            if r >= 30 {
//                redValueOfAllPts.append(Int(r))
//            }
//            i += bytesPerPixel
//        }
        // 取百强红色点
        return redValueOfAllPts.sorted(by: > )
    }
    
    func photoOutput(_ output: AVCapturePhotoOutput, willCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
        AudioServicesDisposeSystemSoundID(1108)
    }

    func photoOutput(_ output: AVCapturePhotoOutput, didCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
       AudioServicesDisposeSystemSoundID(1108)
    }
}
